package com.javatimes.test.util;

import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

public class DateDeel {

	// 时间日期类函数****************************************************************
	// 这些函数都是基于java.util.date，java.sql.date类型的参数也可填入处理

	/**
	 * 功能说明：两种日期类型转换(java.sql.Date and java.util.Date)
	 * 
	 * @param dDate
	 *            java.util.Date类型的日期
	 * @return java.sql.Date 类型的日期
	 */
	public static java.sql.Date toSqlDate(Date dDate) {
		return new java.sql.Date(dDate.getTime());
	}

	/**
	 * Programmer: Dranson (2005-8-9)
	 * 功能说明：检查字符串是否以比对字符集开头，如果以其中一个开头就返回true，否则返回false
	 * 
	 * @param str
	 *            String 被检查字符串
	 * @param ary
	 *            String[] 比对字符集
	 * @return boolean 是否以比对字符集开头
	 */
	public static boolean oneStart(String str, String[] ary) {
		for (int i = 0; i < ary.length; i++) {
			if (str.startsWith(ary[i]))
				return true;
		}
		return false;
	}

	/**
	 * 功能说明：检查字符串是否以比对字符集开头，如果以其中一个开头就返回true，否则返回false
	 * 
	 * @param str
	 *            String 被检查字符串
	 * @param arys
	 *            String 比对字符集(多个字符串用英文逗号间隔)
	 * @return boolean 是否以比对字符集开头
	 */
	public static boolean oneStart(String str, String arys) {
		return oneStart(str, arys.split(","));
	}

	/**
	 * 功能说明：检查字符串是否以比对字符集结尾，如果以其中一个结尾就返回true，否则返回false
	 * 
	 * @param str
	 *            String 被检查字符串
	 * @param ary
	 *            String[] 比对字符集
	 * @return boolean 是否以比对字符集结尾
	 */
	public static boolean oneEnd(String str, String[] ary) {
		for (int i = 0; i < ary.length; i++) {
			if (str.endsWith(ary[i]))
				return true;
		}
		return false;
	}

	/**
	 * 功能说明：检查字符串是否以比对字符集结尾，如果以其中一个结尾就返回true，否则返回false
	 * 
	 * @param str
	 *            String 被检查字符串
	 * @param arys
	 *            String 比对字符集(多个字符串用英文逗号间隔)
	 * @return boolean 是否以比对字符集结尾
	 */
	public static boolean oneEnd(String str, String arys) {
		return oneEnd(str, arys.split(","));
	}

	/**
	 * 功能说明：检查字符串是否包含比对字符集，如果包含其中一个就返回true，否则返回false
	 * 
	 * @param str
	 *            String 被检查字符串
	 * @param ary
	 *            String[] 比对字符集
	 * @return boolean
	 */
	public static boolean oneOf(String str, String[] ary) {
		for (int i = 0; i < ary.length; i++) {
			if (str.indexOf(ary[i]) > -1)
				return true;
		}
		return false;
	}

	/**
	 * 功能说明：检查字符串是否包含比对字符集，如果包含其中一个就返回true，否则返回false
	 * 
	 * @param str
	 *            String 被检查字符串
	 * @param arys
	 *            String 比对字符集(多个字符串用英文逗号间隔)
	 * @return boolean
	 */
	public static boolean oneOf(String str, String arys) {
		if ((arys == null || arys.trim().equalsIgnoreCase("")) && str != null
				&& !str.trim().equalsIgnoreCase(""))
			return false;// 比对字符集为空直接返回false
		return oneOf(str, arys.split(","));
	}

	/**
	 * 功能说明：检查字符串是否等于比对字符集，如果等于其中一个就返回true，否则返回false
	 * 
	 * @param str
	 *            String 被检查字符串
	 * @param ary
	 *            String[] 比对字符集
	 * @return boolean
	 */
	public static boolean oneCase(String str, String[] ary) {
		for (int i = 0; i < ary.length; i++) {
			if (str.equalsIgnoreCase(ary[i]))
				return true;
		}
		return false;
	}

	/**
	 * 功能说明：检查字符串是否等于比对字符集，如果等于其中一个就返回true，否则返回false
	 * 
	 * @param str
	 *            String 被检查字符串
	 * @param arys
	 *            String 比对字符集(多个字符串用英文逗号间隔)
	 * @return boolean
	 */
	public static boolean oneCase(String str, String arys) {
		return oneCase(str, arys.split(","));
	}

	/**
	 * 功能说明：字符串类型的日期转换为java.util.Date类型的日期
	 * 类似vb的CDate函数，自动分析sDate，如格式正常，返回日期，否则报错。
	 * 注意这里只能处理单纯日期，不处理时间，年份正常范围在0-99和1000－9999 仅解析用/-.间隔的日期
	 * 
	 * @param sDate
	 *            java.util.String类型的日期
	 * @exception Exception
	 *                非法日期格式！
	 * @return 返回转换后的日期对象
	 */
	public static Date toDate(String sDate) throws Exception {
		int jj;
		char ss, cc;
		String[] sss = { "-", "/", "." };
		String[] result;
		int kk, mm;
		final String emsg = "非法日期格式！";

		GregorianCalendar cl = null;

		// 检查分隔符
		for (jj = 0; jj < sss.length; jj++) {
			if (sDate.indexOf(sss[jj]) >= 0)
				break;
		}
		if (jj >= sss.length)
			throw new Exception(emsg);

		ss = sss[jj].charAt(0);
		// 检查数字有效性即除了数字和分隔符，不应该再包括其它字符
		for (int i = 0; i < sDate.length(); i++) {
			cc = sDate.charAt(i);
			if (cc != ss && (cc < '0' || cc > '9'))
				throw new Exception(emsg);
		}

		// 劈开，获取3个数字
		result = sDate.split(sss[jj], -1); // 检查全部，包括空的元素，用0会忽略空
		if (result.length != 3)
			throw new Exception(emsg);
		jj = Integer.parseInt(result[0]);
		kk = Integer.parseInt(result[1]);
		mm = Integer.parseInt(result[2]);

		// 判断是否符合一种日期格式
		// 1、y/M/d格式
		if (isValidDate(jj, kk, mm))
			cl = new GregorianCalendar(jj < 30 ? jj + 2000
					: (jj <= 99 ? jj + 1900 : jj), kk - 1, mm);
		else {
			if (mm < 30)
				mm += 2000;
			else if (mm <= 99)
				mm += 1900;
			// 2、M/d/y格式
			if (isValidDate(mm, jj, kk))
				cl = new GregorianCalendar(mm, jj - 1, kk);
			// 3、d/M/y格式
			else if (isValidDate(mm, kk, jj))
				cl = new GregorianCalendar(mm, kk - 1, jj);
			else
				throw new Exception(emsg);
		}
		return cl.getTime();
	}

	/**
	 * 功能说明：判断年月日是否在正常范围 年份正常范围在0-99和1000－9999
	 * 
	 * @param year
	 *            年份值
	 * @param month
	 *            月份值
	 * @param day
	 *            天数值
	 * @return 判断年月日是否在正常范围
	 */
	public static boolean isValidDate(int year, int month, int day) {
		GregorianCalendar cl;

		if (year < 0 || (year > 99 && (year < 1000 || year > 9999)))
			return false;
		if (year < 30)
			year += 2000;
		else if (year <= 99)
			year += 1900;

		if (month < 1 || month > 12)
			return false;

		cl = new GregorianCalendar(year, month - 1, 1); // 参数月份从0开始所以减一
		if (day < cl.getActualMinimum(Calendar.DAY_OF_MONTH)
				|| day > cl.getActualMaximum(Calendar.DAY_OF_MONTH))
			return false;

		return true;
	}

	/**
	 * 功能说明：得到年份(月份getMonth，日getDay，星期getWeekDay) 包装了GregorianCalendar类的get方法
	 * Calendar类中定义了月份，星期几的常数。 注意月份常数0开始，一般不要使用
	 * 
	 * @param dDate
	 *            传日的日期对象
	 * @return int年份
	 */
	public static int getYear(Date dDate) {
		return getDateItems(dDate, Calendar.YEAR);
	}

	/**
	 * 功能说明：得到年份(月份getMonth，日getDay，星期getWeekDay) 包装了GregorianCalendar类的get方法
	 * Calendar类中定义了月份，星期几的常数。 注意月份常数0开始，一般不要使用
	 * 
	 * @param dDate
	 *            传日的日期对象
	 * @return int得到月份
	 */
	public static int getMonth(Date dDate) {
		return getDateItems(dDate, Calendar.MONTH) + 1;
	}

	/**
	 * 功能说明：得到年份(月份getMonth，日getDay，星期getWeekDay) 包装了GregorianCalendar类的get方法
	 * Calendar类中定义了月份，星期几的常数。 注意月份常数0开始，一般不要使用
	 * 
	 * @param dDate
	 *            传日的日期对象
	 * @return int日
	 */
	public static int getDay(Date dDate) {
		return getDateItems(dDate, Calendar.DAY_OF_MONTH);
	}

	/**
	 * 功能说明：得到年份(月份getMonth，日getDay，星期getWeekDay) 包装了GregorianCalendar类的get方法
	 * Calendar类中定义了月份，星期几的常数。 注意月份常数0开始，一般不要使用
	 * 
	 * @param dDate
	 *            传日的日期对象
	 * @return int星期几
	 */
	public static int getWeekDay(Date dDate) {
		return getDateItems(dDate, Calendar.DAY_OF_WEEK);
	}

	/**
	 * 功能说明：返回日期中的任何元素
	 * 
	 * @param field
	 *            ：Calendar类中的常数，如YEAR/MONTH/DAY_OF_MONTH... <br>
	 *            <b><big>注意返回的month一月份是从0开始的！</big></b>
	 */
	public static final int getDateItems(Date dDate, int field) {
		GregorianCalendar cl = new GregorianCalendar();
		cl.setTime(dDate);
		return cl.get(field);
	}

	/**
	 * 功能说明：在给定日期时间上，增加天数
	 * 
	 * @param dDate
	 *            传入日期
	 * @param days
	 *            增加的天数
	 * @return 返回增加天数后的日期
	 */
	public static final Date addDay(Date dDate, int days) {
		return addDate(dDate, days, Calendar.DAY_OF_MONTH);
	}

	/**
	 * 功能说明：加减月，根据日期向前或向后推算N个月
	 * 
	 * @param dDate
	 *            日期
	 * @param months
	 *            月份数 正整数或负整数
	 * @return 返回增加月份后的日期对象
	 * */
	public static final Date addMonth(Date dDate, int months) {
		return addDate(dDate, months, Calendar.MONTH);
	}

	/**
	 * 功能说明：加减年，根据日期向前或向后推算N年
	 * 
	 * @param dDate
	 *            日期
	 * @param years
	 *            年份数 正整数或负整数
	 * @return 返回增加年份后的日期对象
	 * */
	public static final Date addYear(Date dDate, int years) {
		return addDate(dDate, years, Calendar.YEAR);
	}

	/**
	 * 功能说明：加减日期
	 * 
	 * @param 日期对象
	 * @param field指定是年
	 *            、月、日
	 * @param amount是数量
	 * @return 修改后的日期
	 */
	public static Date addDate(Date dDate, int amount, int field) {
		GregorianCalendar cl = new GregorianCalendar();
		cl.setTime(dDate);
		cl.add(field, amount);

		return cl.getTime();
	}

	/**
	 * 功能说明：通过只算年份和月份，获取月份差，不计四舍五入
	 * 
	 * @param dDate1
	 *            Date：起始月
	 * @param dDate2
	 *            Date：终止月
	 * @return int：dDate2-dDate1的月份差
	 */
	public static int monthDiff(java.util.Date dDate1, java.util.Date dDate2) {
		int year, month;
		GregorianCalendar cld = new GregorianCalendar();

		cld.setTime(dDate2);
		year = cld.get(Calendar.YEAR);
		month = cld.get(Calendar.MONTH);

		cld.setTime(dDate1);
		year -= cld.get(Calendar.YEAR);
		month -= cld.get(Calendar.MONTH);

		return year * 12 + month;
	}

	/**
	 * 功能说明：通过只算年份和月份，获取月份差，不计四舍五入
	 * 
	 * @param dDate2
	 *            Date：终止月
	 * @return int：dDate2-当前日期的月份差
	 */
	public static int monthDiff(java.util.Date dDate2) {
		return monthDiff(new java.util.Date(), dDate2);
	}

	/**
	 * 功能说明：判断闰年
	 * 
	 * @param year
	 *            传入得年份值
	 * @return new GregorianCalendar().isLeapYear(year) 是否为闰年;
	 */
	public static boolean isLeapYear(int year) {
		return new GregorianCalendar().isLeapYear(year);
	}

	/**
	 * 功能说明：判断闰年
	 * 
	 * @param dDate
	 *            传入日期对象
	 * @return 是否为闰年;
	 */
	public static boolean isLeapYear(Date dDate) {
		GregorianCalendar cl = new GregorianCalendar();
		cl.setTime(dDate);
		return cl.isLeapYear(cl.get(Calendar.YEAR));
	}

	/**
	 * 功能说明：获取指定年份范围内的闰年数
	 * 
	 * @param startYear
	 *            ：起始年（包含）
	 * @param endYear
	 *            ：结束年（包含）
	 * @return 指定年份范围内的闰年数
	 */
	public static int getLeapYears(int startYear, int endYear) {
		int count = 0;
		GregorianCalendar cl = new GregorianCalendar();
		for (int i = startYear; i <= endYear; i++)
			if (cl.isLeapYear(i))
				count++;
		return count;
	}

	/**
	 * 功能说明：月末日28/29/30/31？ 使用GregorianCalendar.getActualMaximum
	 * 
	 * @param year
	 *            传入年
	 * @param month
	 *            月
	 * @return 指定年份、月份的月末日
	 */
	public static int endOfMonth(int year, int month) {
		return new GregorianCalendar(year, month - 1, 1)
				.getActualMaximum(Calendar.DAY_OF_MONTH);
	}

	public static int endOfMonth(Date dDate) {
		GregorianCalendar cl = new GregorianCalendar();
		cl.setTime(dDate);
		return cl.getActualMaximum(Calendar.DAY_OF_MONTH);
	}

	// 数字类函数********************************************************************
	// (因为金额小数只有两位，所以double可以表示足够大的数据)

	/**
	 * 判断是否数值 Decimal
	 */
	public static boolean isNumeric(String sNum) {
		try {
			toNumber(sNum);
			return true;
		} catch (Exception ye) {
			return false;
		}
	}

	/**
	 * 自动分析sNum格式，解析成double类型返回 支持千分符，科学计数，百分数...前后空格，前导的+号和0 遇其它非法格式报错
	 * 
	 * @param sNum
	 *            要转换为double类型的字符串
	 * @exception Exception
	 *                非法数值格式！
	 * @return double类型的数字
	 */
	public static double toNumber(String sNum) throws Exception {
		int i = 0;
		DecimalFormat df = new DecimalFormat(sNum.indexOf("%") > 0 ? "#,###.#%"
				: "#,###.#E0");

		try {
			sNum = trim(sNum);
			if (sNum.length() > 1)
				if (sNum.charAt(0) == '0') { // 去前导连续0，注意只有一个0的情况
					if (sNum.charAt(1) != '.')
						for (i = 0; i < sNum.length() - 1; i++)
							if (sNum.charAt(i) != '0')
								break;
				} else if (sNum.charAt(0) == '+')
					i = 1;

			return df.parse(
					i == 0 || sNum.indexOf("%") > 0 ? sNum : sNum.substring(i))
					.doubleValue();
		} catch (Exception pe) {
			throw new Exception("非法数值格式！", pe);
		}
	}

	/**
	 * 功能说明：把字符串变双精度，格式不对返回0，不报错
	 * 
	 * @param sNum
	 *            String 字符串
	 * @return double 返回值
	 */
	public static double toDouble(String sNum) {
		try {
			return toNumber(sNum);
		} catch (Exception e) {
			return 0.0;
		}
	}

	/**
	 * 功能说明：把字符串变整数，格式不对返回0，不报错
	 * 
	 * @param sNum
	 *            String 字符串
	 * @return int 返回值
	 */
	public static int toInt(String sNum) {
		try {
			return (int) toNumber(sNum);
		} catch (Exception e) {
			return 0;
		}
	}

	public static final String formatNumber(long number, String format) {
		return (new DecimalFormat(format)).format(number);
	}

	// 字符串类函数********************************************************************
	/** java可以实现left,right,mid，可是如果超过长度，会报错，这里提供容错版本 */

	/**
	 * 功能说明：从给定字符串的左侧截取子字符串
	 * 
	 * @param sSrc
	 *            给定字符串
	 * @param iLen
	 *            截取长度
	 * @return 子字符串
	 */
	public static final String left(String sSrc, int iLen) {
		if (iLen >= sSrc.length())
			return sSrc;
		return sSrc.substring(0, iLen);
	}

	/**
	 * 功能说明：从给定字符串的右侧截取子字符串
	 * 
	 * @param sSrc
	 *            给定字符串
	 * @param iLen
	 *            截取长度
	 * @return 子字符串
	 */
	public static final String right(String sSrc, int iLen) {
		if (iLen >= sSrc.length())
			return sSrc;
		return sSrc.substring(sSrc.length() - iLen);
	}

	/**
	 * 功能说明：给定字符串，从指定位置开始，截取固定长度的子字符串
	 * 
	 * @param sSrc
	 *            传入字符串
	 * @param iStart
	 *            开始位置
	 * @param iLen
	 *            截取长度
	 * @return 子字符串
	 */
	public static final String mid(String sSrc, int iStart, int iLen) {
		if (iStart + iLen >= sSrc.length())
			return sSrc.substring(iStart);
		return sSrc.substring(iStart, iStart + iLen);
	}

	/**
	 * 功能说明：从给定字符串的指定位置截取子串
	 * 
	 * @param sSrc
	 *            传入字符串
	 * @param iStart
	 *            开始位置
	 * @return 截取的子字符串
	 */
	public static final String mid(String sSrc, int iStart) {
		return sSrc.substring(iStart);
	}

	/**
	 * 功能说明：去除字符串尾部空格
	 * 
	 * @param sSrc
	 *            String：源串
	 * @return String：去除尾部空格后的结果
	 */
	public static final String rTrim(String sSrc) {
		int i;

		for (i = sSrc.length() - 1; i >= 0; i--)
			if (sSrc.charAt(i) != ' ')
				break;
		if (i < 0)
			return "";
		return sSrc.substring(0, i + 1);
	}

	/**
	 * 功能说明：去除字符串开头空格
	 * 
	 * @param sSrc
	 *            String：源串
	 * @return String：去除开头空格后的结果
	 */
	public static final String lTrim(String sSrc) {
		int len = sSrc.length();
		int i;

		for (i = 0; i < len; i++)
			if (sSrc.charAt(i) != ' ')
				break;
		if (i >= len)
			return "";
		return sSrc.substring(i);
	}

	/**
	 * 功能说明：去除字符串首尾的空格
	 * 
	 * @param sSrc
	 *            String：源串
	 * @return String：去除空格后的结果串
	 */
	public static final String trim(String sSrc) {
		int i, j;
		// 去除尾部空格
		for (i = sSrc.length() - 1; i >= 0; i--)
			if (sSrc.charAt(i) != ' ')
				break;
		if (i < 0)
			return "";
		// 去除开头空格
		for (j = 0; j < i; j++) {
			if (sSrc.charAt(j) != ' ')
				break;
		}
		return sSrc.substring(j, i + 1);// 返回从j到i的字符
	}

	/**
	 * 其实string的split方法，如果limit参数为负数，也可以显示这一功能，只是默认是0
	 * 
	 * 代替java的String类的split方法，即使最后以分隔符结束，也能正确返回最后的空串
	 * 
	 * @param sSrc
	 *            String：要split的原始串
	 * @param delimiter
	 *            String：分隔符
	 * @return String[]：返回字符串数组
	 */
	public static final String[] split(String sSrc, String delimiter) {
		String[] sarr;
		int l, len;

		sarr = java.util.regex.Pattern.compile(delimiter, 0).split(sSrc + " ",
				0);
		l = sarr.length - 1;
		len = sarr[l].length();
		if (len <= 1)
			sarr[l] = "";
		else
			sarr[l] = sarr[l].substring(0, len - 1);
		return sarr;
	}

	/**
	 * 功能说明：将指定范围的数组元素组合起来成一个字符串
	 * 
	 * @param sArr
	 *            String[]
	 * @param delimiter
	 *            String：连接字符
	 * @param iStart
	 *            int：起始元素位置
	 * @param iEnd
	 *            int：截止元素
	 * @return String：组合成的字符串
	 */
	public static final String join(String[] sArr, String delimiter,
			int iStart, int iEnd) {
		StringBuffer buf = new StringBuffer();

		for (int i = (iStart != 0 ? iStart : 0); i < (iEnd != 0 ? iEnd + 1
				: sArr.length); i++)
			buf.append(delimiter).append(sArr[i]);

		return (buf.length() > 0 && delimiter.length() > 0 ? buf
				.substring(delimiter.length()) : buf.toString());
	}

	/**
	 * 功能说明：将指定范围的数组元素组合起来成一个字符串
	 * 
	 * @param sArr
	 *            String[]
	 * @param delimiter
	 *            String：连接字符
	 * @param iStart
	 *            int：起始元素位置
	 * @return String：组合成的字符串
	 */
	public static final String join(String[] sArr, String delimiter, int iStart) {
		return join(sArr, delimiter, iStart, 0);
	}

	/**
	 * 功能说明：将指定范围的数组元素组合起来成一个字符串
	 * 
	 * @param sArr
	 *            String[]
	 * @param delimiter
	 *            String：连接字符
	 * @return String：组合成的字符串
	 */
	public static final String join(String[] sArr, String delimiter) {
		return join(sArr, delimiter, 0, 0);
	}

	/**
	 * 功能说明：查询返回字符串中“6”之前的字符相加的int值，没有“6”时，返回0
	 * 
	 * @param strAccLen
	 * @return
	 */
	public static int getStart(String strAccLen) {
		int iStart = 0;
		for (int i = 0, j = strAccLen.indexOf("6"); i < j; i++) {
			iStart += strAccLen.charAt(i) - '0';
		}
		return iStart;
	}

	/**
	 * jdk1.5中contains函数
	 * 
	 * @param String
	 *            str_1 供查找的字符串库
	 * @param String
	 *            str_2 查找包含的字符串 kcontains("abc,bca,cbz","abc")
	 * @return boolean
	 * */
	public static boolean kcontains(String str_1, String str_2) {
		boolean b_result = false;
		char[] stra_1 = str_1.toCharArray();
		char[] stra_2 = str_2.toCharArray();
		int i_index = 0;
		int i_length = stra_2.length;
		int i_end = stra_1.length - i_length;
		while (i_index <= i_end) {
			int i_temp = i_index;
			int i_TrueFlag = 0;
			for (int i = 0; i < i_length; i++) {
				if (stra_2[i] == stra_1[i_temp]) {
					i_TrueFlag++;
				} else {
					break;
				}
				if (i_TrueFlag == i_length)
					return true;
				i_temp++;
			}
			i_index++;
		}
		return b_result;
	}

}
